/* ----------------------------------------------------------------------
 * $Date:        5. February 2013
 * $Revision:    V1.02
 *
 * Project:      CMSIS-RTOS API
 * Title:        cmsis_os.h header file
 *
 *----------------------------------------------------------------------------
 *---------------------------------------------------------------------------*/

#include "tx_api.h"
#include "stdint.h"

#ifndef _CMSIS_OS_H
#define _CMSIS_OS_H

/// \note MUST REMAIN UNCHANGED: \b osCMSIS identifies the CMSIS-RTOS API version.
#define osCMSIS 0x10002 ///< API version (main [31:16] .sub [15:0])

/// \note CAN BE CHANGED: \b osCMSIS_KERNEL identifies the underlying RTOS kernel and version number.
#define osCMSIS_KERNEL 0x10000 ///< RTOS identification and version (main [31:16] .sub [15:0])

/// \note MUST REMAIN UNCHANGED: \b osKernelSystemId shall be consistent in every CMSIS-RTOS.
#define osKernelSystemId "KERNEL V1.00" ///< RTOS identification string

/// \note MUST REMAIN UNCHANGED: \b osFeature_xxx shall be consistent in every CMSIS-RTOS.
#define osFeature_MainThread 1 ///< main thread      1=main can be thread, 0=not available
#define osFeature_Pool 1	   ///< Memory Pools:    1=available, 0=not available
#define osFeature_MailQ 1	   ///< Mail Queues:     1=available, 0=not available
#define osFeature_MessageQ 1   ///< Message Queues:  1=available, 0=not available
#define osFeature_Signals 8	   ///< maximum number of Signal Flags available per thread
#define osFeature_Semaphore 1  ///< osFeature_Semaphore function: 1=available, 0=not available
#define osFeature_Wait 0	   ///< osWait function: 1=available, 0=not available
#define osFeature_SysTick 1	   ///< osKernelSysTick functions: 1=available, 0=not available

#ifdef __cplusplus
extern "C"
{
#endif

	// ==== Enumeration, structures, defines ====

	/// Priority used for thread control.
	/// \note MUST REMAIN UNCHANGED: \b osPriority shall be consistent in every CMSIS-RTOS.
	typedef enum
	{
		osPriorityIdle = 28,		///< priority: idle (lowest)
		osPriorityLow = 25,			///< priority: low
		osPriorityBelowNormal = 20, ///< priority: below normal
		osPriorityNormal = 15,		///< priority: normal (default)
		osPriorityAboveNormal = 10, ///< priority: above normal
		osPriorityHigh = 5,			///< priority: high
		osPriorityRealtime = 1,		///< priority: realtime (highest)
		osPriorityError = 0			///< system cannot determine priority or thread has illegal priority
	} osPriority;

/// Timeout value.
/// \note MUST REMAIN UNCHANGED: \b osWaitForever shall be consistent in every CMSIS-RTOS.
#define osWaitForever 0xFFFFFFFF ///< wait forever timeout value

	/// Status code values returned by CMSIS-RTOS functions.
	/// \note MUST REMAIN UNCHANGED: \b osStatus shall be consistent in every CMSIS-RTOS.
	typedef enum
	{
		osOK = 0,						///< function completed; no error or event occurred.
		osEventSignal = 0x08,			///< function completed; signal event occurred.
		osEventMessage = 0x10,			///< function completed; message event occurred.
		osEventMail = 0x20,				///< function completed; mail event occurred.
		osEventTimeout = 0x40,			///< function completed; timeout occurred.
		osErrorParameter = 0x80,		///< parameter error: a mandatory parameter was missing or specified an incorrect object.
		osErrorResource = 0x81,			///< resource not available: a specified resource was not available.
		osErrorTimeoutResource = 0xC1,	///< resource not available within given time: a specified resource was not available within the timeout period.
		osErrorISR = 0x82,				///< not allowed in ISR context: the function cannot be called from interrupt service routines.
		osErrorISRRecursive = 0x83,		///< function called multiple times from ISR with same object.
		osErrorPriority = 0x84,			///< system cannot determine priority or thread has illegal priority.
		osErrorNoMemory = 0x85,			///< system is out of memory: it was impossible to allocate or reserve memory for the operation.
		osErrorValue = 0x86,			///< value of a parameter is out of range.
		osErrorOS = 0xFF,				///< unspecified RTOS error: run-time error but no other error message fits.
		os_status_reserved = 0x7FFFFFFF ///< prevent from enum down-size compiler optimization.
	} osStatus;

#if (INCLUDE_eTaskGetState == 1)
	/* Thread state returned by osThreadGetState */
	typedef enum
	{
		osThreadRunning = 0x0,	 /* A thread is querying the state of itself, so must be running. */
		osThreadReady = 0x1,	 /* The thread being queried is in a read or pending ready list. */
		osThreadBlocked = 0x2,	 /* The thread being queried is in the Blocked state. */
		osThreadSuspended = 0x3, /* The thread being queried is in the Suspended state, or is in the Blocked state with an infinite time out. */
		osThreadDeleted = 0x4,	 /* The thread being queried has been deleted, but its TCB has not yet been freed. */
		osThreadError = 0x7FFFFFFF
	} osThreadState;
#endif /* INCLUDE_eTaskGetState */

	/// Timer type value for the timer definition.
	/// \note MUST REMAIN UNCHANGED: \b os_timer_type shall be consistent in every CMSIS-RTOS.
	typedef enum
	{
		osTimerOnce = 0,	///< one-shot timer
		osTimerPeriodic = 1 ///< repeating timer
	} os_timer_type;

	/// Entry point of a thread.
	/// \note MUST REMAIN UNCHANGED: \b os_pthread shall be consistent in every CMSIS-RTOS.
	typedef void (*os_pthread)(void const *argument);

	/// Entry point of a timer call back function.
	/// \note MUST REMAIN UNCHANGED: \b os_ptimer shall be consistent in every CMSIS-RTOS.
	typedef void (*os_ptimer)(void const *argument);

	// >>> the following data type definitions may shall adapted towards a specific RTOS

	/// Thread ID identifies the thread (pointer to a thread control block).
	/// \note CAN BE CHANGED: \b os_thread_cb is implementation specific in every CMSIS-RTOS.
	typedef TX_THREAD *osThreadId;

	/// Timer ID identifies the timer (pointer to a timer control block).
	/// \note CAN BE CHANGED: \b os_timer_cb is implementation specific in every CMSIS-RTOS.
	typedef TX_TIMER *osTimerId;

	/// Mutex ID identifies the mutex (pointer to a mutex control block).
	/// \note CAN BE CHANGED: \b os_mutex_cb is implementation specific in every CMSIS-RTOS.
	typedef TX_MUTEX *osMutexId;

	/// Semaphore ID identifies the semaphore (pointer to a semaphore control block).
	/// \note CAN BE CHANGED: \b os_semaphore_cb is implementation specific in every CMSIS-RTOS.
	typedef TX_SEMAPHORE *osSemaphoreId;

	/// Pool ID identifies the memory pool (pointer to a memory pool control block).
	/// \note CAN BE CHANGED: \b os_pool_cb is implementation specific in every CMSIS-RTOS.
	typedef struct os_pool_cb *osPoolId;

	/// Message ID identifies the message queue (pointer to a message queue control block).
	/// \note CAN BE CHANGED: \b os_messageQ_cb is implementation specific in every CMSIS-RTOS.
	typedef TX_QUEUE *osMessageQId;

	/// Mail ID identifies the mail queue (pointer to a mail queue control block).
	/// \note CAN BE CHANGED: \b os_mailQ_cb is implementation specific in every CMSIS-RTOS.
	typedef struct os_mailQ_cb *osMailQId;

	typedef TX_THREAD osStaticThreadDef_t;
	typedef TX_TIMER osStaticTimerDef_t;
	typedef TX_MUTEX osStaticMutexDef_t;
	typedef TX_SEMAPHORE osStaticSemaphoreDef_t;
	typedef TX_QUEUE osStaticMessageQDef_t;

	typedef TX_QUEUE *osQueneId;
	typedef TX_EVENT_FLAGS_GROUP *osEventId;

	/// Thread Definition structure contains startup information of a thread.
	/// \note CAN BE CHANGED: \b os_thread_def is implementation specific in every CMSIS-RTOS.
	typedef struct os_thread_def
	{
		char *name;						   ///< Thread name
		os_pthread pthread;				   ///< start address of thread function
		long tpriority;					   ///< initial thread priority
		uint32_t instances;				   ///< maximum number of instances of that thread function
		uint32_t stacksize;				   ///< stack size requirements in bytes; 0 is default stack size
		void *buffer;					   ///< stack buffer for static allocation; NULL for dynamic allocation
		osStaticThreadDef_t *controlblock; ///< control block to hold thread's data for static allocation; NULL for dynamic allocation
	} osThreadDef_t;

	/// Timer Definition structure contains timer parameters.
	/// \note CAN BE CHANGED: \b os_timer_def is implementation specific in every CMSIS-RTOS.
	typedef struct os_timer_def
	{
		char *name;
		os_ptimer ptimer;				  ///< start address of a timer function
		osStaticTimerDef_t *controlblock; ///< control block to hold timer's data for static allocation; NULL for dynamic allocation
	} osTimerDef_t;

	/// Mutex Definition structure contains setup information for a mutex.
	/// \note CAN BE CHANGED: \b os_mutex_def is implementation specific in every CMSIS-RTOS.
	typedef struct os_mutex_def
	{
		char *name;
		osStaticMutexDef_t *controlblock; ///< control block for static allocation; NULL for dynamic allocation
	} osMutexDef_t;

	/// Semaphore Definition structure contains setup information for a semaphore.
	/// \note CAN BE CHANGED: \b os_semaphore_def is implementation specific in every CMSIS-RTOS.
	typedef struct os_semaphore_def
	{
		char *name;
		osStaticSemaphoreDef_t *controlblock; ///< control block for static allocation; NULL for dynamic allocation
	} osSemaphoreDef_t;

	/// Definition structure for memory block allocation.
	/// \note CAN BE CHANGED: \b os_pool_def is implementation specific in every CMSIS-RTOS.
	typedef struct os_pool_def
	{
		uint32_t pool_sz; ///< number of items (elements) in the pool
		uint32_t item_sz; ///< size of an item
		void *pool;		  ///< pointer to memory for pool
	} osPoolDef_t;

	/// Definition structure for message queue.
	/// \note CAN BE CHANGED: \b os_messageQ_def is implementation specific in every CMSIS-RTOS.
	typedef struct os_messageQ_def
	{
		char *name;
		uint32_t queue_sz;					 ///< number of elements in the queue
		uint32_t item_sz;					 ///< size of an item
		void *buffer;						 ///< buffer for static allocation; NULL for dynamic allocation
		osStaticMessageQDef_t *controlblock; ///< control block to hold queue's data for static allocation; NULL for dynamic allocation
											 // void                       *pool;    ///< memory array for messages
	} osMessageQDef_t;

	/// Definition structure for mail queue.
	/// \note CAN BE CHANGED: \b os_mailQ_def is implementation specific in every CMSIS-RTOS.
	typedef struct os_mailQ_def
	{
		uint32_t queue_sz; ///< number of elements in the queue
		uint32_t item_sz;  ///< size of an item
		struct os_mailQ_cb **cb;
	} osMailQDef_t;

	/// Event structure contains detailed information about an event.
	/// \note MUST REMAIN UNCHANGED: \b os_event shall be consistent in every CMSIS-RTOS.
	///       However the struct may be extended at the end.
	typedef struct
	{
		osStatus status; ///< status code: event or error information
		union
		{
			uint32_t v;		 ///< message as 32-bit value
			void *p;		 ///< message or mail as void pointer
			int32_t signals; ///< signal flags
		} value;			 ///< event value
		union
		{
			osMailQId mail_id;		 ///< mail id obtained by \ref osMailCreate
			osMessageQId message_id; ///< message id obtained by \ref osMessageCreate
		} def;						 ///< event definition
	} osEvent;

//  ==== Kernel Control Functions ====
#define osKernelInitialize(...)
	osStatus osKernelStart(void);
#define osKernelRunning(...)

/// \return RTOS kernel system timer as 32-bit value
#define osKernelSysTick tx_time_get
#define osKernelSysTickFrequency (TX_TIMER_TICKS_PER_SECOND)

/// \return time value normalized to the \ref osKernelSysTickFrequency
#define osKernelSysTickMicroSec(microsec) ((x * TX_TIMER_TICKS_PER_SECOND + 999) / 1000)

//  ==== Thread Management ====

/// Create a Thread Definition with function, priority, and stack requirements.
/// \param         name         name of the thread function.
/// \param         priority     initial priority of the thread function.
/// \param         instances    number of possible thread instances.
/// \param         stacksz      stack size (in bytes) requirements for the thread function.
/// \note CAN BE CHANGED: The parameters to \b osThreadDef shall be consistent but the
///       macro body is implementation specific in every CMSIS-RTOS.
#define osThreadDef(name, thread, priority, instances, stacksz) \
	extern void thread(void const *argument);                   \
	static uint64_t name##_stk[stacksz / 8 + 1];                \
	static osStaticThreadDef_t name##_tcb;                      \
	const osThreadDef_t os_thread_def_##name =                  \
		{#name, (thread), (priority), (instances), (stacksz), (void *)name##_stk, &name##_tcb}

/// Access a Thread definition.
/// \param         name          name of the thread definition object.
/// \note CAN BE CHANGED: The parameter to \b osThread shall be consistent but the
///       macro body is implementation specific in every CMSIS-RTOS.
#define osThread(name) \
	&os_thread_def_##name

	/// Create a thread and add it to Active Threads and set it to state READY.
	/// \param[in]     thread_def    thread definition referenced with \ref osThread.
	/// \param[in]     argument      pointer that is passed to the thread function as start argument.
	/// \return thread ID for reference by other functions or NULL in case of error.
	/// \note MUST REMAIN UNCHANGED: \b osThreadCreate shall be consistent in every CMSIS-RTOS.
	osThreadId osThreadCreate(const osThreadDef_t *thread_def, void *argument);

	extern VOID *_tx_thread_system_stack_ptr;
	extern TX_THREAD *_tx_thread_current_ptr;
	extern TX_THREAD *_tx_thread_created_ptr;
	extern ULONG _tx_thread_created_count;
	extern volatile ULONG _tx_thread_system_state;

/// Return the thread ID of the current running thread.
/// \return thread ID for reference by other functions or NULL in case of error.
/// \note MUST REMAIN UNCHANGED: \b osThreadGetId shall be consistent in every CMSIS-RTOS.
#define osThreadGetId (_tx_thread_current_ptr)

/// Terminate execution of a thread and remove it from Active Threads.
#define osThreadTerminate(...)

/// Pass control to next thread that is in state \b READY.
#define osThreadYield(...)

	/// Change priority of an active thread.
	/// \param[in]     thread_id     thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
	/// \param[in]     priority      new priority value for the thread function.
	/// \return status code that indicates the execution status of the function.
	/// \note MUST REMAIN UNCHANGED: \b osThreadSetPriority shall be consistent in every CMSIS-RTOS.
	UINT osThreadSetPriority(osThreadId thread_id, UINT priority);

/// Get current priority of an active thread.
/// \param[in]     thread_id     thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
/// \return current priority value of the thread function.
/// \note MUST REMAIN UNCHANGED: \b osThreadGetPriority shall be consistent in every CMSIS-RTOS.
#define osThreadGetPriority(thread_id) (thread_id->tx_thread_priority)

	//  ==== Generic Wait Functions ====

	/// Wait for Timeout (Time Delay).
	/// \param[in]     millisec      time delay value
	/// \return status code that indicates the execution status of the function.
	osStatus osDelay(uint32_t millisec);

//  ==== Timer Management Functions ====
#define osTimerDef(name, function)               \
	static osStaticTimerDef_t os_timer_cb##name; \
	const osTimerDef_t os_timer_def_##name =     \
		{#name, (function), &os_timer_def_##name}

/// Access a Timer definition.
/// \param         name          name of the timer object.
/// \note CAN BE CHANGED: The parameter to \b osTimer shall be consistent but the
///       macro body is implementation specific in every CMSIS-RTOS.
#define osTimer(name) \
	&os_timer_def_##name

	/// Create a timer.
	/// \param[in]     timer_def     timer object referenced with \ref osTimer.
	/// \param[in]     type          osTimerOnce for one-shot or osTimerPeriodic for periodic behavior.
	/// \param[in]     argument      argument to the timer call back function.
	/// \return timer ID for reference by other functions or NULL in case of error.
	/// \note MUST REMAIN UNCHANGED: \b osTimerCreate shall be consistent in every CMSIS-RTOS.
	osTimerId osTimerCreate(const osTimerDef_t *timer_def, os_timer_type type, void *argument);

	/// Start or restart a timer.
	/// \param[in]     timer_id      timer ID obtained by \ref osTimerCreate.
	/// \param[in]     millisec      time delay value of the timer.
	/// \param[in]     type          osTimerOnce for one-shot or osTimerPeriodic for periodic behavior.
	/// \return status code that indicates the execution status of the function.
	/// \note MUST REMAIN UNCHANGED: \b osTimerStart shall be consistent in every CMSIS-RTOS.
	osStatus osTimerStart(osTimerId timer_id, uint32_t millisec, os_timer_type type);

/// Stop the timer.
#define osTimerStop tx_timer_deactivate

/// Delete a timer that was created by \ref osTimerCreate.
#define osTimerDelete tx_timer_delete

//  ==== Mutex Management ====
#define osMutexDef(name)                             \
	static TX_MUTEX os_mutex_##name = {0};           \
	const struct os_mutex_def os_mutex_str##name = { \
		#name "_mutex",                              \
		&os_mutex_##name}

#define osMutex(name) \
	&os_mutex_str##name

	osMutexId osMutexCreate(const struct os_mutex_def *mutex_def);

#define osMutexWait tx_mutex_get
#define osMutexRelease tx_mutex_put

	osStatus osMutexDelete(osMutexId mutex_id);

	//  ==== Semaphore Management Functions ====

#define osSemaphoreDef(name)                     \
	static osStaticSemaphoreDef_t name##_sem_cb; \
	const osSemaphoreDef_t os_semaphore_def_##name = {#name, 0, &name##_sem_cb}

#define osSemaphore(name) \
	&os_semaphore_def_##name

	osSemaphoreId osSemaphoreCreate(const osSemaphoreDef_t *semaphore_def, int32_t count);

	int32_t osSemaphoreWait(osSemaphoreId semaphore_id, uint32_t millisec);
	osStatus osSemaphoreRelease(osSemaphoreId semaphore_id);
	osStatus osSemaphoreDelete(osSemaphoreId semaphore_id);

	//  ==== Memory Pool Management Functions ====

	//  ==== Message Queue Management Functions ====

#if (defined(osFeature_MessageQ) && (osFeature_MessageQ != 0)) // Message Queues available

	/// \brief Create a Message Queue Definition.
	/// \param         name          name of the queue.
	/// \param         queue_sz      maximum number of messages in the queue.
	/// \param         type          data type of a single message element (for debugger).
	/// \note CAN BE CHANGED: The parameter to \b osMessageQDef shall be consistent but the
	///       macro body is implementation specific in every CMSIS-RTOS.

#define osMessageQDef(name, queue_sz, type)        \
	static uint32_t name##buff[queue_sz];          \
	static osStaticMessageQDef_t name##qcb;        \
	const osMessageQDef_t os_messageQ_def_##name = \
		{#name, (queue_sz), sizeof(type), name##buff, &name##qcb}

/// \brief Access a Message Queue Definition.
/// \param         name          name of the queue
/// \note CAN BE CHANGED: The parameter to \b osMessageQ shall be consistent but the
///       macro body is implementation specific in every CMSIS-RTOS.
#define osMessageQ(name) \
	&os_messageQ_def_##name

	/// Create and Initialize a Message Queue.
	/// \param[in]     queue_def     queue definition referenced with \ref osMessageQ.
	/// \param[in]     thread_id     thread ID (obtained by \ref osThreadCreate or \ref osThreadGetId) or NULL.
	/// \return message queue ID for reference by other functions or NULL in case of error.
	/// \note MUST REMAIN UNCHANGED: \b osMessageCreate shall be consistent in every CMSIS-RTOS.
	osMessageQId osMessageCreate(const osMessageQDef_t *queue_def, osThreadId thread_id);

	/// Put a Message to a Queue.
	/// \param[in]     queue_id      message queue ID obtained with \ref osMessageCreate.
	/// \param[in]     info          message information.
	/// \param[in]     millisec      timeout value or 0 in case of no time-out.
	/// \return status code that indicates the execution status of the function.
	/// \note MUST REMAIN UNCHANGED: \b osMessagePut shall be consistent in every CMSIS-RTOS.
	osStatus osMessagePut(osMessageQId queue_id, uint32_t info, uint32_t millisec);

	/// Get a Message or Wait for a Message from a Queue.
	/// \param[in]     queue_id      message queue ID obtained with \ref osMessageCreate.
	/// \param[in]     millisec      timeout value or 0 in case of no time-out.
	/// \return event information that includes status code.
	/// \note MUST REMAIN UNCHANGED: \b osMessageGet shall be consistent in every CMSIS-RTOS.
	osEvent osMessageGet(osMessageQId queue_id, uint32_t millisec);

/**
 * @brief Delete a Message Queue
 * @param  queue_id  message queue ID obtained with \ref osMessageCreate.
 * @retval  status code that indicates the execution status of the function.
 */
#define osMessageDelete tx_queue_delete

#endif // Message Queues available

//  ==== Mail Queue Management Functions ====

/**
 * @brief  Suspend execution of a thread.
 * @param   thread_id   thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
 * @retval  status code that indicates the execution status of the function.
 */
#define osThreadSuspend tx_thread_suspend

/**
 * @brief  Resume execution of a suspended thread.
 * @param   thread_id   thread ID obtained by \ref osThreadCreate or \ref osThreadGetId.
 * @retval  status code that indicates the execution status of the function.
 */
#define osThreadResume tx_thread_resume

/**
 * @brief  Suspend execution of a all active threads.
 * @retval  status code that indicates the execution status of the function.
 */
#define osThreadSuspendAll(...)

/**
 * @brief  Resume execution of a all suspended threads.
 * @retval  status code that indicates the execution status of the function.
 */
#define osThreadResumeAll(...)

#ifdef __cplusplus
}
#endif

#endif // _CMSIS_OS_H
